"use strict";

var request = require('request').defaults({jar: true}),
    logger = require('./logger').getLogger('wechat_bot.log'),
    utils = require('util'),
    tool = require('./tool');

//require('request-debug')(request);

var logVerbose = (text) => logger.log('verbose', text);
var logInfo = (text) => logger.info(text);
var logError = (text) => logger.error(text);

const LOGIN_WEXIN_DOMAIN = 'https://login.weixin.qq.com';
const WX_QQ_DOMAIN = 'https://wx.qq.com';
const WX2_QQ_DOMAIN = 'https://wx2.qq.com';
const WEBPUSH_WEIXIN_QQ_DOMAIN = 'https://webpush.wx2.qq.com';

/**
 * 获取
 * @type {Promise}
 */
var getUUID = new Promise(function (resolve, reject) {
    var param = {
        appid: 'wx782c26e4c19acffb',
        //redirect_uri: 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage',
        fun: 'new',
        lang: 'zh_CN',
        _: Date.now()
    }

    var uri = '/jslogin';

    var options = {
        uri: uri,
        baseUrl: LOGIN_WEXIN_DOMAIN,
        method: 'GET',
        qs: param
    }

    var req = request(options, function (err, response, body) {
        logVerbose(body);
        if (err) return reject(err);
        resolve(body);
    });
});

/**
 * 检查和解析结果
 * @param body
 * @returns {boolean}
 */
function checkAndParseUUID(body) {
    // [^"] 表示除了"以外的所有字符串
    let [all, code, uuid] = /window.QRLogin.code = (\d+); window.QRLogin.uuid = "([^"]+)";/.exec(body);
    logInfo(all);
    logInfo(code);
    logInfo(uuid);
    if (!uuid || !code || code != '200') {
        return false;
    }
    return uuid;
}

/**
 * 生产登录二维码图片
 * @param display
 * @returns {function(*=)}
 */
function showQRImg(wxSession) {
    var socket = wxSession.socket;
    var display = wxSession.display;
    var server = wxSession.server;
    return (uuid) => {
        console.log("请扫描二维码并确认登录，关闭二维码窗口继续。" + uuid);
        var uri = '/qrcode/' + uuid;
        var QRImgUrl = LOGIN_WEXIN_DOMAIN + uri;

        var checkLoginPromise = new Promise(function (resolve, reject) {
            console.log("GET" + QRImgUrl);
            var req = request(QRImgUrl, {
                agentOptions: {keepAlive: true},
                encoding: null
            }, function (error, response, body) {
                if (error) {
                    return reject(err);
                }
                resolve({
                    uuid: uuid,
                    display: display,
                    tip: 1, // 标识
                    server: server,
                    socket: socket
                });
                socket.write(body);
            });
            /*req.pipe(socket, {end: false});*/
            /*req.on('error', (err) => {
                console.log(err);
                return reject(err);
            });*/
        });

        return checkLoginPromise;

    }
}

/**
 * 检查二维码扫描的情况
 * @param wxsession 微信会话对象
 * @returns {Promise}
 */
function checkLogin(wxsession) {
    var now = ~Date.now();
    var tip = wxsession.tip;
    var uuid = wxsession.uuid;
    var display = wxsession.display;
    var server = wxsession.server;
    var socket = wxsession.socket;
    return new Promise((resolve, reject) => {
        var uri = 'cgi-bin/mmwebwx-bin/login';

        var options = {
            uri: uri,
            baseUrl: LOGIN_WEXIN_DOMAIN,
            method: 'GET',
            qs: {
                loginicon: true,
                uuid: uuid,
                tip: tip,
                r: now
            },
            agentOptions: {keepAlive: true}
        }

        var req = request(options, function (err, response, body) {
            logVerbose(body);
            if (err) {
                return reject(err);
            }
            logVerbose('checkLogin ' + body);
            if (/window\.code=200/.test(body)) {
                logInfo('登录微信');
                // 删除主进程对子进程exit事件的回调，并且退出子进程（就是想把那个二维码图片退出）
                display.removeListener('exit', wechatSessionFailure);
                socket.destroy();
                server.close(() => {
                    logInfo('server服务已经关闭。')
                });
                display.kill();
                resolve(body);
            } else if (/window\.code=201/.test(body)) {
                wxsession.tip = 0;  // 第一次之后tip都为0，不然下一个请求不是长连接
                logInfo('已扫描，请点击确认按钮登录');
                resolve(checkLogin(wxsession));
            } else if (/window\.code=408/.test(body)) {
                wxsession.tip = 0;
                logInfo('本次http连接超时，重新发起请求');
                resolve(checkLogin(wxsession));
            } else {
                logError('二维码已失效');
                display.kill();
                wechatSessionFailure(1);
            }
        });
    });
}

/**
 * 解析以及返回重点向位置
 * @param body
 */
function parseAndRedirect(body) {
    let [all, redirectUrl] = /window.redirect_uri="([^"]+)";/.exec(body);
    if (!redirectUrl) {
        logError("无重定向地址");
        wechatSessionFailure(1);
    }
    console.log("获取变量redirect:" + redirectUrl);
    return redirectUrl;
}

/**
 * 登录
 * @param redirectUrl 登录地址
 * @returns {Promise}
 */
function wxLogin(redirectUrl) {
    logVerbose(`redirectUrl :${redirectUrl}`);
    var wxSession = Object.create(null);
    wxSession.wxJar = request.jar();
    return new Promise((resolve, reject) => {
        var option = {
            url: redirectUrl,
            //jar: wxSession.jar,
            followRedirect: false,
            agentOptions: {
                keepAlive: true
            },
            headers: {
                'Host': 'wx.qq.com'
            }
        }
        request(option, (error, response, body) => {
            // 之后的操作需要cookie
            if (error) {
                return reject(error);
            }
            logVerbose(response.statusCode);
            wxSession.loginBody = body;
            wxSession.cookies = response.headers['set-cookie'];
            resolve(wxSession);
        });
    });
}

/**
 * 解析xml结果
 * @param wxSession
 * @returns {*}
 */
var getBaseRequest = (wxSession) => {
    logInfo(wxSession);
    var loginBody = wxSession.loginBody;
    let [all, ret] = new RegExp('<ret>([^><]+)</ret>').exec(loginBody);
    if (ret != 0) {
        let [all_message, message] = new RegExp('<message>([^><]+)</message>').exec(loginBody);
        logError(message);
        wechatSessionFailure(0);
    }
    let [all0, skey] = new RegExp('<skey>([^><]+)</skey>').exec(loginBody);
    let [all1, wxsid] = new RegExp('<wxsid>([^><]+)</wxsid>').exec(loginBody);
    let [all2, wxuin] = new RegExp('<wxuin>([^><]+)</wxuin>').exec(loginBody);
    let [all3, pass_ticket] = new RegExp('<pass_ticket>([^><]+)</pass_ticket>').exec(loginBody);
    wxSession.BaseRequest = {
        Skey: skey,
        Sid: wxsid,
        Uin: wxuin
    }
    wxSession.pass_ticket = pass_ticket;
    return wxSession;
}

/**
 * 初始化数据，这里可以获取到常联系人的信息和自己的基本信息
 * @param wxSession
 * @returns {Promise}
 */
var webWechatInit = (wxSession) => {
    console.log('登录之后，开始进行初始化工作');
    wxSession.groupContact = Object.create(null);
    return new Promise((resolve, reject) => {
        var options = {
            baseUrl: WX2_QQ_DOMAIN,
            uri: `/cgi-bin/mmwebwx-bin/webwxinit?lang=en_US&pass_ticket=${wxSession.pass_ticket}`,
            method: 'POST',
            body: {BaseRequest: wxSession.BaseRequest},
            json: true,
            agentOptions: {keepAlive: true},
            headers: {
                'Accept': '*/*',
                'Connection': 'keep-alive',
                'Host': 'wx2.qq.com',
                //'Cookie': wxSession.cookies
            },
            //jar: wxSession.wxJar
        }
        logInfo(options.method + " " + options.baseUrl + options.uri);
        var req = request(options, (error, response, body) => {
            if (error) {
                return reject(error);
            }
            wxSession.username = body['User']['UserName'];
            wxSession.nickname = body['User']['NickName'];
            wxSession.SyncKey = body['SyncKey'];
            resolve(wxSession);
        });
    });
}

/**
 * 获得联系人
 * @param wxSession
 * @returns {Promise}
 */
var webWechatGetContact = (wxSession) => {
    console.log("初始化成功，获取联系人...")
    return new Promise((resolve, reject) => {
        var skey = wxSession.BaseRequest.Skey;
        var pass_ticket = wxSession.pass_ticket;
        // var jsonFile = fs.createWriteStream('contact.json');
        var timestamp = Date.now();
        var options = {
            baseUrl: WX2_QQ_DOMAIN,
            //uri: `/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket=${pass_ticket}&r=${timestamp}&seq=0&skey=${skey}`,
            uri: `/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=en_US&pass_ticket=${pass_ticket}`,
            method: 'POST',
            body: {BaseRequest: wxSession.BaseRequest},
            json: true,
            agentOptions: {
                keepAlive: true
            },
            headers: {
                'Host': 'wx2.qq.com',
                //'Cookie': wxSession.cookies
            },
            //jar: wxSession.wxJar,
        }
        logInfo(options.method + "---" + options.baseUrl + options.uri);
        request(options, (error, response, body) => {
            if (error) {
                return reject(error);
            }
            if (!body || body.BaseResponse.Ret !== 0) {
                logInfo('获取联系人失败: ' + utils.inspect(body));
                resolve(wxSession);
                return;
            }
            logVerbose(body)
            // fs.writeFile('contact.json', JSON.stringify(body));
            wxSession.memberList = body.MemberList;
            //wxSession.toUser = memberList.filter(m=>(m.NickName == "核心活动都是玩玩玩吃吃吃的北邮GC"))[0]['UserName'];
            console.log("联系人获取完毕...");
            console.log("<--OK-->");
            resolve(wxSession);
        });
    });
}

/**
 * 消息检查
 * @param wxSession
 * @returns {Promise}
 */
var synccheck = (wxSession) => {
    return new Promise((resolve, reject) => {
        // FIXME: 每次开始的时候进行检查，是否合适？
        if (wxSession.socketFail >= 5) {
            reject(new Error('微信连接socket错误太多(maybe network lost)'));
            wechatSessionFailure(3);
            return;
        }
        // 重置wxSession.webwxsync,默认不需要webwxsync
        wxSession.webwxsync = false;
        var timestamp = Date.now();
        var skey = wxSession.BaseRequest.Skey;
        var sid = wxSession.BaseRequest.Sid;
        var uin = wxSession.BaseRequest.Uin;
        var deviceId = 'e' + ('' + Math.random().toFixed(15).substring(2, 17));
        wxSession.BaseRequest.DeviceID = deviceId;
        var synckey = wxSession.SyncKey.List.map(o => o.Key + '_' + o.Val).join('|');
        var options = {
            baseUrl: WEBPUSH_WEIXIN_QQ_DOMAIN,
            uri: '/cgi-bin/mmwebwx-bin/synccheck',
            method: 'GET',
            qs: {
                r: timestamp,
                skey: skey,
                sid: sid,
                uin: uin,
                deviceid: deviceId,
                synckey: synckey,
                _: Date.now()
            },
            forever: true,
            headers: {
                'Host': 'webpush.wx2.qq.com',
                'Referer': 'https://wx2.qq.com/',
                'Connection': 'keep-alive',
                'Cookie': wxSession.cookies // FIXME 就差个cookies导致一直返回1102，但是require('request').defaults({jar: true})不是会自动带上cookie吗？
            },
            timeout: 35000
        }

        logInfo(options.method + '---' + options.baseUrl + options.uri);
        logInfo(options.qs);
        request(options, (error, response, body) => {
            wxSession.webwxsync = false;
            console.log('synccheck');
            console.log(error);
            console.log(body)
            if (error || !(/retcode:"0"/.test(body))) {
                wxSession.socketFail = (wxSession.socketFail || 0) + 1;
                resolve(wxSession);
                return;
            }
            // 正常
            wxSession.socketFail = 0;
            if (body == 'window.synccheck={retcode:"1101",selector:"0"}') {
                logError('服务器断开连接，退出程序。');
                reject(new Error('wxSessionStop'));
            } else if (body !== 'window.synccheck={retcode:"0",selector:"0"}') {
                // 标识有没有新消息，要不要websync
                wxSession.webwxsync = true;
            } else {
                wxSession.webwxsync = false;
            }
            resolve(wxSession);
        });
    });
}

/**
 * 获取最新消息
 * @param handleMsg
 * @returns {function(*)}
 */
var webwxsync = (handleMsg) => {
    return (wxSession) => {
        if (!wxSession.webwxsync) {
            return Promise.resolve(wxSession);
        }
        return new Promise((resolve, reject) => {
            var pass_ticket = wxSession.pass_ticket;
            var rr = ~Date.now();
            var options = {
                baseUrl: WX2_QQ_DOMAIN,
                uri: `/cgi-bin/mmwebwx-bin/webwxsync?sid=${wxSession.BaseRequest.Sid}&skey=${wxSession.BaseRequest.Skey}&lang=en_US&pass_ticket=${pass_ticket}&rr=${rr}`,
                method: 'POST',
                body: {
                    BaseRequest: wxSession.BaseRequest,
                    SyncKey: wxSession.SyncKey
                },
                json: true,
                headers: {
                    'Host': 'wx2.qq.com',
                },
                timeout: 15e3
            }
            logInfo(options.method + "---" + options.baseUrl + options.uri)
            request(options, (error, response, body) => {
                if (error) {
                    logError('webwxsync获取最新信息有误' + utils.inspect(error));
                    resolve(wxSession);
                    return;
                }
                if (!body || body.BaseResponse.Ret !== 0) {
                    logError('webwxsync获取不到任何数据' + utils.inspect(error));
                    resolve(wxSession);
                    return;
                }
                // 更新SyncKey
                wxSession.SyncKey = body.SyncKey;
                // TODO:更新联系人
                tool.constructor(body.ModContactList, wxSession);
                // 消息处理更新
                handleMsg(body.AddMsgList, wxSession);
                resolve(wxSession);
            });
        });
    }
}

/**
 * 发送信息
 * @param msg
 * @param toUser
 * @param wxSession
 */
function webwxsendmsg(msg, toUser, wxSession) {
    var msgId = (Date.now() + Math.random().toFixed(3)).replace('.', '');
    var pass_ticket = wxSession.pass_ticket;
    var options = {
        baseUrl: WX2_QQ_DOMAIN,
        uri: `/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket=${pass_ticket}`,
        method: 'POST',
        json: true,
        body: {
            BaseRequest: wxSession.BaseRequest,
            Msg: {
                "Type": 1,
                "Content": msg,
                "FromUserName": wxSession.username,
                "ToUserName": toUser,
                "LocalID": msgId,
                "ClientMsgId": msgId
            }
        }
    }
    logInfo("webwxsendmsg:" + options.method + " " + options.baseUrl + options.uri);
    logInfo(options.body);
    var req = request(options, (error, response, body) => {
        console.log(body);
        if (!error) {
            console.log("发送-> ", msg);
        }
    });
}

/**
 * 批量获取用户信息（也可以获取群信息）
 * @param username
 * @param wxSession
 * @returns {Promise}
 */
var webwxbatchgetcontact = (username, wxSession) => {
    var pass_ticket = wxSession.pass_ticket;
    var timestamp = Date.now();
    return new Promise((resolve, reject) => {
        var options = {
            baseUrl: WX2_QQ_DOMAIN,
            uri: `/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&r=${timestamp}&pass_ticket=${pass_ticket}`,
            method: 'POST',
            json: true,
            body: {
                BaseRequest: wxSession.BaseRequest,
                Count: 1,
                List: [
                    {
                        UserName: username,
                        EncryChatRoomId: ''
                    }
                ]
            }
        }
        request(options, (error, response, body) => {
            console.log(body)
            if (error || !body) {
                return reject(error);
            }
            if (body.BaseResponse.Ret != 0) {
                return reject(body.BaseResponse.ErrMsg);
            }
            if (!(username.startsWith('@@'))) { //用户
                console.log('更新用户缓存');
                wxSession.memberList.push(body.ContactList[0]);
            } else { //群
                // 缓存起来
                console.log('更新群缓存');
                var group = body.ContactList[0];
                var groupRealName = group.NickName;
                var memberList = group.MemberList;
                wxSession.groupContact[username] = {
                    memberList: memberList,
                    nickName: groupRealName,
                };
                resolve(wxSession);
            }
        });
    });
}


/**
 * 错误处理
 * @param code
 * @param signal
 */
function wechatSessionFailure(code, signal) {
    logError('结束会话');
    throw new Error('wxSessionStop:' + code);
}

exports.getUUID = getUUID;
exports.checkAndParseUUID = checkAndParseUUID;
exports.showQRImg = showQRImg;
exports.checkLogin = checkLogin;
exports.parseAndRedirect = parseAndRedirect;
exports.wxLogin = wxLogin;
exports.getBaseRequest = getBaseRequest;
exports.webWechatInit = webWechatInit;
exports.webWechatGetContact = webWechatGetContact;
exports.synccheck = synccheck;
exports.webwxsync = webwxsync;
exports.webwxsendmsg = webwxsendmsg;
exports.webwxbatchgetcontact = webwxbatchgetcontact;